#pragma once

namespace _hHuffmanDetail
{
	struct Node;

	struct CodeEx1Callback
	{
		struct _StrFreqTabVal
		{
			size_t _freq = 0;
			Node* _node = NULL;
		};

		using _Str = hStrView;
		using _StrHash = HHash<_Str>;
		using _Intv = hInterval<size_t>;
		using _IntvVec = std::vector<hInterval<size_t>>;
		using _StrWtTab = std::unordered_map<_Str, _IntvVec, _StrHash>;
		using _WtTab = std::multimap<size_t, _IntvVec, std::greater<size_t>>;
		using _StrFreqTab = std::unordered_map<_Str, _StrFreqTabVal, _StrHash>;
		using _StrFreqTabIt = _StrFreqTab::iterator;
		using _SegTab = hIntervalMap<size_t, _StrFreqTabIt>;
		using _FreqTab = std::multimap<size_t, Node*>;

		hBitStr& _outData;
		const char* _inDt = NULL;
		size_t _len = 0;
		Node* _pTree = NULL;
		Node* _pLenTree = NULL;
		_StrWtTab _strWeightTab;
		_StrFreqTab _tmpStrFreqTab;
		_WtTab _weightTab;
		_SegTab _segmentIntv;
		_FreqTab _strfreqTab;
		std::multimap<size_t, Node*> _lenFreqTab;
		std::map<size_t, hBitStr> _lenKeyTab;

		void operator() ();

	private:
		void init();
		void show();
		void fin();
		void code();

		void showTreeCb(Node* pTree) const;
		void genStrKeyCb(Node* pTree = NULL, hBitStr val = hBitStr{});
		void genLenKeyCb(Node* pTree = NULL, hBitStr val = hBitStr{});
		void codeStrTreeCb(const Node* pTree = NULL);
		void codeLenTreeCb(const Node* pTree = NULL);
	};

	struct DecodeEx1Callback
	{
		const hBitStr& _inBit;
		hBitView _view{ _inBit };
		size_t _len = 0;
		Node* _pStrTree = NULL;
		Node* _pLenTree = NULL;

		template <typename T>
		void operator() (T& outDt);

	private:
		void init();
		void show();
		void fin();
		void decode(std::string& outDt);

		void genLenTreeCb(Node** pPTree = NULL);
		void genStrTreeCb(Node** pPTree = NULL);
		void finCb(const Node* pTree);
		size_t getLenCb(const Node* pTree = NULL);
		void showTreeCb(Node* pTree) const;
	};
}
